home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / vm / vmSysCall.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  35.5 KB  |  1,273 lines

  1. /*
  2.  * vmSysCall.c -
  3.  *
  4.  *     This file contains routines that handle virtual memory system
  5.  *    calls.
  6.  *
  7.  * Copyright (C) 1985 Regents of the University of California
  8.  * All rights reserved.
  9.  */
  10.  
  11.  
  12. #ifndef lint
  13. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/vm/vmSysCall.c,v 9.23 92/08/20 21:57:59 shirriff Exp $ SPRITE (Berkeley)";
  14. #endif not lint
  15.  
  16. #include <sprite.h>
  17. #include <vm.h>
  18. #include <vmInt.h>
  19. #include <lock.h>
  20. #include <user/vm.h>
  21. #include <sync.h>
  22. #include <sys.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <fs.h>
  26. #include <fsio.h>
  27. #include <sys/mman.h>
  28. #include <stdio.h>
  29. #include <bstring.h>
  30.  
  31. extern Vm_SharedSegTable sharedSegTable;
  32. char     *sprintf();
  33.  
  34. int vmShmDebug = 0;    /* Shared memory debugging flag. */
  35.  
  36. extern int   debugFsStubs; /* Unix compatibility debug flags. */
  37. extern int   debugProcStubs;
  38. extern int   debugSigStubs;
  39. extern int   debugSysStubs;
  40. extern int   debugTimerStubs;
  41. extern int   debugVmStubs;
  42.  
  43. /*
  44.  * Forward declaration.
  45.  */
  46. static ReturnStatus VmMunmapInt _ARGS_((Address startAddr, int length,
  47.     int noError));
  48.  
  49. /*
  50.  * VmVirtAddrParseUnlock calls VmVirtAddrParse and then unlocks
  51.  * the heap page table if necessary, since VmVirtAddrParse may
  52.  * lock it.
  53.  */
  54. #define VmVirtAddrParseUnlock(procPtr, startAddr, virtAddrPtr) \
  55.     {VmVirtAddrParse(procPtr,startAddr, virtAddrPtr); \
  56.     if ((virtAddrPtr)->flags & VM_HEAP_PT_IN_USE) \
  57.         { VmDecPTUserCount(procPtr->vmPtr->segPtrArray[VM_HEAP]); } }
  58.  
  59. /*
  60.  * Test if an address is not page aligned.
  61.  */
  62. #define BADALIGN(addr) (((int)(addr))&(vm_PageSize-1))
  63.  
  64.  
  65. /*
  66.  *----------------------------------------------------------------------
  67.  *
  68.  * Vm_PageSize --
  69.  *
  70.  *    Return the hardware page size.
  71.  *
  72.  * Results:
  73.  *    Status from copying the page size out to user space.
  74.  *
  75.  * Side effects:
  76.  *    Copy page size out to user address space.
  77.  *
  78.  *----------------------------------------------------------------------
  79.  */
  80. ReturnStatus
  81. Vm_PageSize(pageSizePtr)
  82.     int    *pageSizePtr;
  83. {
  84.     int            pageSize = vm_PageSize;
  85.  
  86.     return(Vm_CopyOut(4, (Address) &pageSize, (Address) pageSizePtr));
  87. }
  88.  
  89.  
  90. /***************************************************************************
  91.  *
  92.  *    The following two routines, Vm_CreateVA and Vm_DestroyVA, are used
  93.  *    to allow users to add or delete ranges of valid virtual addresses
  94.  *    from their virtual address space.  Since neither of these routiens
  95.  *    are monitored (although they call monitored routines), there are 
  96.  *    potential synchronization problems for users sharing memory who
  97.  *    expand their heap segment.  The problems are caused if two or more
  98.  *    users attempt to simultaneously change the size of the heap segment 
  99.  *    to different sizes. The virtual memory system will not have any 
  100.  *    problems handling the conflicting requests, however the actual range 
  101.  *    of valid virtual addresses is unpredictable.  It is up to the user
  102.  *    to synchronize when expanding the HEAP segment.
  103.  */
  104.  
  105.  
  106. /*
  107.  *----------------------------------------------------------------------
  108.  *
  109.  * Vm_CreateVA --
  110.  *
  111.  *    Validate the given range of addresses.  If necessary the segment
  112.  *    is expanded to make room.
  113.  *
  114.  * Results:
  115.  *    VM_WRONG_SEG_TYPE if tried to validate addresses for a stack or
  116.  *    code segment and VM_SEG_TOO_LARGE if the segment cannot be
  117.  *    expanded to fill the size.
  118.  *
  119.  * Side effects:
  120.  *    None.
  121.  *
  122.  *----------------------------------------------------------------------
  123.  */
  124.  
  125. ReturnStatus
  126. Vm_CreateVA(address, size)
  127.     Address address;    /* Address to validate from. */
  128.     int        size;    /* Number of bytes to validate. */
  129. {
  130.     register Vm_Segment *segPtr;
  131.     int            firstPage, lastPage;
  132.     Proc_ControlBlock    *procPtr;
  133.  
  134.     procPtr = Proc_GetCurrentProc();
  135.     firstPage = (unsigned) (address) >> vmPageShift;
  136.     lastPage = (unsigned) ((int) address + size - 1) >> vmPageShift;
  137.  
  138.     segPtr = (Vm_Segment *) procPtr->vmPtr->segPtrArray[VM_HEAP];
  139.  
  140.     /*
  141.      * Make sure that the beginning address falls into the heap segment and
  142.      * not the code segment.
  143.      */
  144.     if (firstPage < segPtr->offset) {
  145.     return(VM_WRONG_SEG_TYPE);
  146.     }
  147.  
  148.     /*
  149.      * Make sure that the ending page is not greater than the highest
  150.      * possible page.  Since there must be one stack page and one page
  151.      * between the stack and the heap, the highest possible heap page is
  152.      * mach_LastUserStackPage - 2 or segPtr->maxAddr, whichever is lower.
  153.      */
  154.     if (lastPage > mach_LastUserStackPage - 2 ||
  155.         address + size - 1 > segPtr->maxAddr) {
  156.     return(VM_SEG_TOO_LARGE);
  157.     }
  158.  
  159.     /*
  160.      * Make pages between firstPage and lastPage part of the heap segment's
  161.      * virtual address space.
  162.      */
  163.     return(VmAddToSeg(segPtr, firstPage, lastPage));
  164. }
  165.  
  166.  
  167. /*
  168.  *----------------------------------------------------------------------
  169.  *
  170.  * Vm_DestroyVA --
  171.  *
  172.  *    Invalidate the given range of addresses.  If the starting address
  173.  *    is too low then an error message is returned.
  174.  *
  175.  * Results:
  176.  *    VM_WRONG_SEG_TYPE if tried to invalidate addresses for a code.
  177.  *
  178.  * Side effects:
  179.  *    None.
  180.  *
  181.  *----------------------------------------------------------------------
  182.  */
  183.  
  184. ReturnStatus
  185. Vm_DestroyVA(address, size)
  186.     Address address;    /* Address to validate from. */
  187.     int        size;    /* Number of bytes to validate. */
  188. {
  189.     register Vm_Segment *segPtr;
  190.     int            firstPage, lastPage;
  191.     Proc_ControlBlock    *procPtr;
  192.  
  193.     procPtr = Proc_GetCurrentProc();
  194.     firstPage = (unsigned) (address) >> vmPageShift;
  195.     lastPage = (unsigned) ((int) address + size - 1) >> vmPageShift;
  196.  
  197.     segPtr = (Vm_Segment *) procPtr->vmPtr->segPtrArray[VM_HEAP];
  198.  
  199.     /*
  200.      * Make sure that the beginning address falls into the 
  201.      * heap segment.
  202.      */
  203.     if (firstPage < segPtr->offset) {
  204.     return(VM_WRONG_SEG_TYPE);
  205.     }
  206.  
  207.     /*
  208.      * Make pages between firstPage and lastPage not members of the segment's
  209.      * virtual address space.
  210.      */
  211.     return(Vm_DeleteFromSeg(segPtr, firstPage, lastPage));
  212. }
  213.  
  214. static int    copySize = 4096;
  215.  
  216. #ifndef CLEAN
  217. static char    buffer[8192];
  218. #endif CLEAN
  219.  
  220. void    SetVal();
  221.  
  222. /*
  223.  * The # construct to turn a variable into a string is not handled correctly
  224.  * on the current ds3100 (non-ansi) compiler/preprocessor set up.
  225.  * This will change when it's handled correctly.
  226.  */
  227. #if defined(__STDC__)
  228. #define SETVAR(var, val) SetVal(#var, val, (int *)&(var))
  229. #else
  230. #define    SETVAR(var, val) SetVal("var", val, (int *)&(var))
  231. #endif /* sun4 */
  232.  
  233.  
  234. /*
  235.  *----------------------------------------------------------------------
  236.  *
  237.  * Vm_Cmd --
  238.  *
  239.  *      This routine allows a user level program to give commands to
  240.  *      the virtual memory system.
  241.  *
  242.  * Results:
  243.  *      None.
  244.  *
  245.  * Side effects:
  246.  *      Some parameter of the virtual memory system will be modified.
  247.  *
  248.  *----------------------------------------------------------------------
  249.  */
  250. ReturnStatus
  251. Vm_Cmd(command, arg)
  252.     int        command;
  253.     int         arg;
  254. {
  255.     int            numBytes;
  256.     ReturnStatus    status = SUCCESS;
  257.     int            numModifiedPages;
  258.  
  259.     switch (command) {
  260.     case VM_COUNT_DIRTY_PAGES:
  261.         numModifiedPages = VmCountDirtyPages();
  262.         if (Vm_CopyOut(sizeof(int), (Address) &numModifiedPages,
  263.                (Address) arg) != SUCCESS) {
  264.         status = SYS_ARG_NOACCESS;
  265.         }
  266.         break;
  267.     case VM_FLUSH_SEGMENT: {
  268.         extern int    vmNumSegments;
  269.         int        intArr[3];
  270.         Vm_Segment    *segPtr;
  271.         int        lowPage;
  272.         int        highPage;
  273.         Vm_VirtAddr    virtAddr;
  274.  
  275.         status = Vm_CopyIn(3 * sizeof(int), (Address)arg, 
  276.                 (Address)intArr);
  277.         if (status != SUCCESS) {
  278.         break;
  279.         }
  280.         if (intArr[0] <= 0 || intArr[0] >= vmNumSegments) {
  281.         status = SYS_INVALID_ARG;
  282.         break;
  283.         }
  284.         segPtr = VmGetSegPtr(intArr[0]);
  285.         if (segPtr->type == VM_STACK) {
  286.         lowPage = mach_LastUserStackPage - segPtr->numPages + 1;
  287.         highPage = mach_LastUserStackPage;
  288.         } else {
  289.         lowPage = segPtr->offset;
  290.         highPage = segPtr->offset + segPtr->numPages - 1;
  291.         }
  292.         if (intArr[1] >= lowPage && intArr[1] <= highPage) {
  293.         lowPage = intArr[1];
  294.         }
  295.         if (intArr[2] >= lowPage && intArr[2] <= highPage) {
  296.         highPage = intArr[2];
  297.         }
  298.         virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  299.         virtAddr.segPtr = segPtr;
  300.         virtAddr.page = lowPage;
  301.         VmFlushSegment(&virtAddr, highPage);
  302.         break;
  303.     }
  304.     case VM_SET_FREE_WHEN_CLEAN:
  305.         SETVAR(vmFreeWhenClean, arg);
  306.         break;
  307.     case VM_SET_MAX_DIRTY_PAGES:
  308.         SETVAR(vmMaxDirtyPages, arg);
  309.         break;
  310.     case VM_SET_PAGEOUT_PROCS:
  311.         SETVAR(vmMaxPageOutProcs, arg);
  312.         break;
  313.         case VM_SET_CLOCK_PAGES:
  314.             SETVAR(vmPagesToCheck, arg);
  315.             break;
  316.         case VM_SET_CLOCK_INTERVAL: {
  317.         SETVAR(vmClockSleep, (int) (arg * timer_IntOneSecond));
  318.             break;
  319.     }
  320.     case VM_SET_COPY_SIZE:
  321.         SETVAR(copySize, arg);
  322.         break;
  323. #ifndef CLEAN
  324.     case VM_DO_COPY_IN:
  325.         (void)Vm_CopyIn(copySize, (Address) arg, buffer);
  326.         break;
  327.     case VM_DO_COPY_OUT:
  328.         (void)Vm_CopyOut(copySize, buffer, (Address) arg);
  329.         break;
  330.     case VM_DO_MAKE_ACCESS_IN:
  331.         Vm_MakeAccessible(0, copySize, (Address) arg, &numBytes,
  332.                   (Address *) &arg);
  333.         bcopy((Address) arg, buffer, copySize);
  334.         Vm_MakeUnaccessible((Address) arg, numBytes);
  335.         break;
  336.     case VM_DO_MAKE_ACCESS_OUT:
  337.         Vm_MakeAccessible(0, copySize, (Address) arg, &numBytes,
  338.                   (Address *) &arg);
  339.         bcopy(buffer, (Address) arg, copySize);
  340.         Vm_MakeUnaccessible((Address) arg, numBytes);
  341.         break;
  342. #endif CLEAN
  343.     case VM_GET_STATS: {
  344. #if defined(ds3100) || defined(ds5000)
  345.         extern unsigned int end;
  346.         /*
  347.          * The decstations have a big hole between the initialized data
  348.          * and the heap, so we can't just subtract the kernel beginning
  349.          * from the end.
  350.          */
  351.         vmStat.kernMemPages = (unsigned int) 
  352.         (vmMemEnd - VMMACH_VIRT_CACHED_START + (unsigned int) &end
  353.          - mach_KernStart) / vm_PageSize;
  354. #else
  355.         vmStat.kernMemPages = 
  356.             (unsigned int)(vmMemEnd - mach_KernStart) / vm_PageSize;
  357. #endif
  358.         if (Vm_CopyOut(sizeof(Vm_Stat), (Address) &vmStat, 
  359.                (Address) arg) != SUCCESS) {
  360.         status = SYS_ARG_NOACCESS;
  361.         }
  362.         break;
  363.     }
  364.     case VM_SET_COW:
  365.         /*
  366.          * It's okay to turn on COW when it's off, but not the other
  367.          * way around.
  368.          */
  369.         if (arg || !vm_CanCOW) {
  370.         SETVAR(vm_CanCOW, arg);
  371.         } else {
  372.         status = GEN_INVALID_ARG;
  373.         }
  374.         break;
  375.     case VM_SET_FS_PENALTY:
  376.         if (arg <= 0) {
  377.         /*
  378.          * Caller is setting an absolute penalty.
  379.          */
  380.         SETVAR(vmCurPenalty, -arg);
  381.         } else {
  382.         SETVAR(vmFSPenalty, arg);
  383.         SETVAR(vmCurPenalty, (vmStat.fsMap - vmStat.fsUnmap) / 
  384.                     vmPagesPerGroup * vmFSPenalty);
  385.         }
  386.         break;
  387.     case VM_SET_NUM_PAGE_GROUPS: {
  388.         int    numPages;
  389.         int curGroup;
  390.         numPages = vmPagesPerGroup * vmNumPageGroups;
  391.         if (arg <= 0) {
  392.         status = GEN_INVALID_ARG;
  393.         break;
  394.         }
  395.         SETVAR(vmNumPageGroups, arg);
  396.         SETVAR(vmPagesPerGroup, numPages / vmNumPageGroups);
  397.         curGroup = (vmStat.fsMap - vmStat.fsUnmap) / vmPagesPerGroup;
  398.         SETVAR(vmCurPenalty, curGroup * vmFSPenalty);
  399.         SETVAR(vmBoundary, (curGroup + 1) * vmPagesPerGroup);
  400.         break;
  401.     }
  402.     case VM_SET_ALWAYS_REFUSE:
  403.         SETVAR(vmAlwaysRefuse, arg);
  404.         break;
  405.     case VM_SET_ALWAYS_SAY_YES:
  406.         SETVAR(vmAlwaysSayYes, arg);
  407.         break;
  408.     case VM_RESET_FS_STATS:
  409.         vmStat.maxFSPages = vmStat.fsMap - vmStat.fsUnmap;
  410.         vmStat.minFSPages = vmStat.fsMap - vmStat.fsUnmap;
  411.         break;
  412.     case VM_SET_COR_READ_ONLY:
  413.         SETVAR(vmCORReadOnly, arg);
  414.         break;
  415.     case VM_SET_PREFETCH:
  416.         SETVAR(vmPrefetch, arg);
  417.         break;
  418.     case VM_SET_USE_FS_READ_AHEAD:
  419.         SETVAR(vmUseFSReadAhead, arg);
  420.         break;
  421.     case VM_SET_WRITEABLE_PAGEOUT:
  422.         SETVAR(vmWriteablePageout, arg);
  423.         break;
  424.     case VM_SET_WRITEABLE_REF_PAGEOUT:
  425.         SETVAR(vmWriteableRefPageout, arg);
  426.         break;
  427.     case 1999:
  428.         SETVAR(vmShmDebug, arg);
  429.         break;
  430.     case 1234: /* Temporary unix compatibility hook. */
  431.         SETVAR(debugFsStubs, arg);
  432.         SETVAR(debugProcStubs, arg);
  433.         SETVAR(debugSigStubs, arg);
  434.         SETVAR(debugSysStubs, arg);
  435.         SETVAR(debugTimerStubs, arg);
  436.         SETVAR(debugVmStubs, arg);
  437.         default:
  438.         status = VmMach_Cmd(command, arg);
  439.             break;
  440.     }
  441.  
  442.     return(status);
  443. }
  444.  
  445.  
  446. /*
  447.  *----------------------------------------------------------------------
  448.  *
  449.  * SetVal --
  450.  *
  451.  *      Set a given VM variable.
  452.  *
  453.  * Results:
  454.  *      None.
  455.  *
  456.  * Side effects:
  457.  *      The given variable is set.
  458.  *
  459.  *----------------------------------------------------------------------
  460.  */
  461. void
  462. SetVal(descript, newVal, valPtr)
  463.     char    *descript;
  464.     int        newVal;
  465.     int        *valPtr;
  466. {
  467.     printf("%s val was %d, is %d\n", descript, *valPtr, newVal);
  468.     *valPtr = newVal;
  469. }
  470.  
  471. /*
  472.  *----------------------------------------------------------------------
  473.  *
  474.  * Vm_Mmap --
  475.  *
  476.  *    Map a page.
  477.  *
  478.  * Results:
  479.  *    Status from the map.
  480.  *
  481.  * Side effects:
  482.  *    Maps the page.
  483.  *
  484.  *----------------------------------------------------------------------
  485.  */
  486. /*ARGSUSED*/
  487. ENTRY ReturnStatus
  488. Vm_Mmap(startAddr, length, prot, share, streamID, fileAddr, mappedAddr)
  489.     Address    startAddr;    /* Requested starting virt-addr. */
  490.     int        length;        /* Length of mapped segment. */
  491.     int        prot;        /* Protection for mapped segment. */
  492.     int        share;        /* Private/shared flag. */
  493.     int        streamID;    /* Open file to be mapped. */
  494.     int        fileAddr;    /* Offset into mapped file. */
  495.     Address    *mappedAddr;    /* Mapped address (user space). */
  496. {
  497.     Address mappedAddrInt;
  498.     ReturnStatus status;
  499.  
  500.     status = Vm_MmapInt(startAddr, length, prot, share, streamID, fileAddr,
  501.         &mappedAddrInt);
  502.     if (status==SUCCESS) {
  503.     status = Vm_CopyOut(sizeof(int), (Address)&mappedAddrInt,
  504.         (Address)mappedAddr);
  505.     }
  506.     return status;
  507.     
  508. }
  509.  
  510. /*
  511.  *----------------------------------------------------------------------
  512.  *
  513.  * Vm_MmapInt --
  514.  *
  515.  *    Internal routine for Vm_Mmap.
  516.  *
  517.  * Results:
  518.  *    Status from the map.
  519.  *
  520.  * Side effects:
  521.  *    Maps the page.
  522.  *
  523.  *----------------------------------------------------------------------
  524.  */
  525. /*ARGSUSED*/
  526. ENTRY ReturnStatus
  527. Vm_MmapInt(startAddr, length, prot, share, streamID, fileAddr, mappedAddr)
  528.     Address    startAddr;    /* Requested starting virt-addr. */
  529.     int        length;        /* Length of mapped segment. */
  530.     int        prot;        /* Protection for mapped segment. */
  531.     int        share;        /* Private/shared flag. */
  532.     int        streamID;    /* Open file to be mapped. */
  533.     int        fileAddr;    /* Offset into mapped file. */
  534.     Address    *mappedAddr;    /* Mapped address. */
  535. {
  536.     Proc_ControlBlock    *procPtr;
  537.     Fs_Stream         *streamPtr;
  538.     int            pnum;
  539.     ReturnStatus    status = SUCCESS;
  540.     Fs_Attributes    attr;
  541.     Vm_SharedSegTable    *segTabPtr;
  542.     Vm_Segment        *segPtr;
  543.     Vm_SegProcList    *sharedSeg;
  544.     Fs_Stream         *filePtr;
  545.  
  546.     length = (length+vm_PageSize-1)&~(vm_PageSize-1);
  547.     dprintf("mmap( %x, %d, %d, %d, %d, %d)\n", startAddr, length,
  548.         prot, share, streamID, fileAddr);
  549.  
  550.     if ((share&MAP_TYPE)!=MAP_SHARED && (share&MAP_TYPE)!=MAP_PRIVATE) {
  551.     printf("Vm_Mmap: Invalid share flag %x\n", share);
  552.         return VM_WRONG_SEG_TYPE;
  553.     }
  554.  
  555.     procPtr = Proc_GetCurrentProc();
  556.     status = Fs_GetStreamPtr(procPtr,streamID,&streamPtr);
  557.     dprintf("Vm_Mmap: procPtr: %x  streamID: %d streamPtr: %x\n",
  558.         procPtr,streamID,(int)streamPtr);
  559.     if (status != SUCCESS) {
  560.     printf("Vm_Mmap: Fs_GetStreamPtr failure\n");
  561.     return status;
  562.     }
  563.     if (debugVmStubs) {
  564.     printf("mmap: refCount = %d for stream %x ",
  565.         ((Fs_HandleHeader *)streamPtr)->refCount, streamPtr);
  566.     }
  567.     Fsio_StreamCopy(streamPtr,&filePtr);
  568.     if (debugVmStubs) {
  569.     printf(", after copy refCount = %d\n", ((Fs_HandleHeader *)streamPtr)->refCount);
  570.     }
  571.  
  572.     status = Fs_GetAttrStream(filePtr,&attr);
  573.     if (status != SUCCESS) {
  574.     printf("Vm_Mmap: Fs_GetAttrStream failure\n");
  575.     (void)Fs_Close(filePtr);
  576.     return status;
  577.     }
  578.     dprintf("file: fileNumber %d size %d\n",attr.fileNumber, attr.size);
  579.  
  580.     if (!(attr.type == FS_DEVICE) &&
  581.             (BADALIGN(startAddr) || BADALIGN(fileAddr))) {
  582.         printf("Vm_Mmap: Invalid start or offset\n");
  583.         return VM_WRONG_SEG_TYPE;
  584.     }
  585.     /*
  586.      * Do a device-specific mmap.
  587.      */
  588.     if (attr.type == FS_DEVICE) {
  589.         extern  ReturnStatus    Fsio_DeviceMmap();
  590.  
  591.         (void) Fs_Close(filePtr);               /* Don't need this filePtr. */
  592.         /*
  593.          * Should I really indirect through the file system here?  But that
  594.          * requires adding an mmap switch to all the file system crud.  I'll
  595.          * test it this way first by going straight to Fs_Device stuff.
  596.          */
  597.         status = Fsio_DeviceMmap(streamPtr, startAddr, length, fileAddr,
  598.                 &startAddr);
  599.         if (status == SUCCESS) {
  600.         *mappedAddr = startAddr;
  601.         }
  602.     return status;
  603.     }
  604.  
  605.  
  606.     /* 
  607.      * Check permissions.
  608.      * The rules:
  609.      * The file must have read permissions.
  610.      * We must request read and/or write permissions.
  611.      * If we take a private copy, we can do whatever we want.
  612.      * Otherwise we must have the requested permissions.
  613.      */
  614.     if (attr.type != FS_FILE) {
  615.     printf("Vm_Mmap: not a file\n");
  616.     (void)Fs_Close(filePtr);
  617.     return VM_WRONG_SEG_TYPE;
  618.     }
  619.     if (!(filePtr->flags & FS_READ) || !(prot & (PROT_READ | PROT_WRITE)) ||
  620.         ((share&MAP_TYPE)!=MAP_PRIVATE &&
  621.         (((prot & PROT_WRITE) && !(filePtr->flags & FS_WRITE)) ||
  622.         ((prot & PROT_EXEC) && !(filePtr->flags & FS_EXECUTE))))) {
  623.     printf("Vm_Mmap: protection failure\n");
  624.     printf("flags = %x, prot = %x\n", filePtr->flags, prot);
  625.     (void)Fs_Close(filePtr);
  626.     return VM_WRONG_SEG_TYPE;
  627.     }
  628.  
  629.     LOCK_SHM_MONITOR;
  630.     if (procPtr->vmPtr->sharedSegs == (List_Links *)NIL) {
  631.     dprintf("Vm_Mmap: New proc list\n");
  632.     procPtr->vmPtr->sharedSegs = (List_Links *)
  633.         malloc(sizeof(Vm_SegProcList));
  634.     VmMach_SharedProcStart(procPtr);
  635.     dprintf("Vm_Mmap: sharedStart: %x\n",procPtr->vmPtr->sharedStart);
  636.     List_Init((List_Links *)procPtr->vmPtr->sharedSegs);
  637.     Proc_NeverMigrate(procPtr);
  638.     }
  639.     if (!(share&MAP_FIXED) || startAddr==0) {
  640.     status = VmMach_SharedStartAddr(procPtr, length, &startAddr, 0);
  641.     } else {
  642.     status = VmMach_SharedStartAddr(procPtr, length, &startAddr, 1);
  643.     }
  644.     if (status != SUCCESS) {
  645.     printf("Vm_Mmap: VmMach_SharedStart failure\n");
  646.     UNLOCK_SHM_MONITOR;
  647.     (void)Fs_Close(filePtr);
  648.     return status;
  649.     }
  650.  
  651.     /*
  652.      * See if a shared segment is already using the specified file.
  653.      * If we're making a private copy, we probably need a new segment.
  654.      * (We should probably do something more intelligent about mapping
  655.      * multiple copies of a file into memory.)
  656.      */
  657.     segPtr = (Vm_Segment *) NIL;
  658.     segTabPtr = (Vm_SharedSegTable *) NIL;
  659.     if ((share&MAP_TYPE)!=MAP_PRIVATE) {
  660.     LIST_FORALL((List_Links *)&sharedSegTable, (List_Links *)segTabPtr) {
  661.         if (segTabPtr->serverID == attr.serverID && segTabPtr->domain ==
  662.             attr.domain && segTabPtr->fileNumber == attr.fileNumber) {
  663.         segPtr = segTabPtr->segPtr;
  664.         break;
  665.         }
  666.     }
  667.     }
  668.  
  669. #if 0
  670.     pnum = 10288;    /* Random number, since shared memory shouldn't
  671.                 be using this value */
  672. #else
  673.     pnum = (int)startAddr>>vmPageShift;
  674. #endif
  675.  
  676.     if (segPtr == (Vm_Segment *)NIL) {
  677.     dprintf("Vm_Mmap: New segment\n");
  678.     /*
  679.      * Create a new segment and add to the shared segment list.
  680.      */
  681.     
  682.     segTabPtr = (Vm_SharedSegTable*) malloc(sizeof(Vm_SharedSegTable));
  683.     dprintf("Vm_Mmap: creating new segment\n");
  684.     segTabPtr->segPtr = Vm_SegmentNew(VM_SHARED,(Fs_Stream *)NIL,
  685.         0,length>>vmPageShift,pnum,procPtr);
  686.     if ((share&MAP_TYPE)==MAP_PRIVATE) {
  687.         segTabPtr->segPtr->filePtr = filePtr;
  688.     } else {
  689.         segTabPtr->segPtr->filePtr = (Fs_Stream *)NIL;
  690.         segTabPtr->segPtr->swapFilePtr = filePtr;
  691.         segTabPtr->segPtr->flags |= VM_SWAP_FILE_OPENED;
  692.     }
  693.     segTabPtr->serverID = attr.serverID;
  694.     segTabPtr->domain = attr.domain;
  695.     segTabPtr->fileNumber = attr.fileNumber;
  696.     segTabPtr->refCount = 0;
  697.     dprintf("Vm_Mmap: Validating pages %x to %x\n",
  698.         pnum,pnum+(length>>vmPageShift)-1);
  699.     Vm_ValidatePages(segTabPtr->segPtr,pnum,pnum+(length>>vmPageShift)-1,
  700.         FALSE,TRUE);
  701.     List_Insert((List_Links *)segTabPtr,
  702.         LIST_ATFRONT((List_Links *)&sharedSegTable));
  703.     dprintf("Calling Fs_FileBeingMapped(1)\n");
  704.     Fs_FileBeingMapped(filePtr,1);
  705.     dprintf("Done Fs_FileBeingMapped(1)\n");
  706.     } else {
  707.     int i;
  708.     /*
  709.     startAddr = (Address)(segPtr->offset<<vmPageShift);
  710.     */
  711.     if (length > (segPtr->numPages<<vmPageShift)) {
  712.         dprintf("Vm_Mmap: Enlarging segment: 0 to %d\n",
  713.             ((int)length-1)>>vmPageShift);
  714.         status = VmAddToSeg(segPtr,segPtr->offset,segPtr->offset+
  715.             (length>>vmPageShift)-1);
  716.         if (status != SUCCESS) {
  717.         printf("VmAddToSeg failure\n");
  718.         UNLOCK_SHM_MONITOR;
  719.         (void)Fs_Close(filePtr);
  720.         return status;
  721.         }
  722.     }
  723.     for (i=0;i<32;i++) {
  724.         if (segPtr->ptPtr[i] & VM_VIRT_RES_BIT) {
  725.         dprintf("1");
  726.         } else {
  727.         dprintf("0");
  728.         }
  729.     }
  730.     dprintf("\n");
  731.     if (procPtr->vmPtr->sharedSegs == (List_Links *)NIL ||
  732.         !VmCheckSharedSegment(procPtr,segPtr)) {
  733.         /*
  734.          * Process is not using segment.
  735.          */
  736.         dprintf("Vm_Mmap: Adding reference to proc to segment\n");
  737.         Vm_SegmentIncRef(segPtr,procPtr);
  738.     } else {
  739.         /*
  740.          * Process is already using segment.
  741.          */
  742.         dprintf("Vm_Mmap: Process is using segment.\n");
  743.     }
  744.     /*
  745.      * We don't want to keep the file pointer around, since the
  746.      * shared memory segment already exists.
  747.      */
  748.     if (debugVmStubs) {
  749.         printf("Closing filePtr, refCount = %d\n", 
  750.         ((Fs_HandleHeader *)streamPtr)->refCount);
  751.     }
  752.     (void)Fs_Close(filePtr);
  753.     }
  754.  
  755.     /*
  756.      * Unmap any current mapping at the address range.
  757.      */
  758.     status=VmMunmapInt(startAddr,length,1);
  759.     if (status == SUCCESS) {
  760.     /*
  761.      * Force the mach module to allocate the segment again.
  762.      * (The allocation of shared segments in memory needs to be fixed up.
  763.      * The problem is that we may have multiple segments mapped into
  764.      * the same memory, and thus it is hard to keep track of what's
  765.      * in use).  This should force the segment to be marked as in use.
  766.      * There still may be a problem if part of a segment is unmapped.
  767.      */
  768.     status = VmMach_SharedStartAddr(procPtr, length, &startAddr, 1);
  769.     }
  770.     if (status != SUCCESS) {
  771.     printf("Vm_Mmap: Vm_Munmap failure\n");
  772.     UNLOCK_SHM_MONITOR;
  773.     (void)Fs_Close(filePtr);
  774.     return status;
  775.     }
  776.  
  777.     /*
  778.      * Add the segment to the process's list of shared segments.
  779.      */
  780.     dprintf("Vm_Mmap: Adding segment to list\n");
  781.     sharedSeg = (Vm_SegProcList *)malloc(sizeof(Vm_SegProcList));
  782.     sharedSeg->fd = streamID;
  783.     sharedSeg->stream = filePtr;
  784.     sharedSeg->segTabPtr = segTabPtr;
  785.     segTabPtr->refCount++;
  786.     sharedSeg->addr = startAddr;
  787.     sharedSeg->mappedStart = startAddr;
  788.     dprintf("fileAddr: %x\n",fileAddr);
  789.     sharedSeg->fileAddr = fileAddr;
  790.     sharedSeg->offset = (int)startAddr>>vmPageShift;
  791.     sharedSeg->mappedEnd = startAddr+length-1;
  792.     sharedSeg->prot = (prot&PROT_WRITE) ? 0 : VM_READONLY_SEG;
  793.     dprintf("Set prot to %d\n",sharedSeg->prot);
  794.     if ((int)sharedSeg->segTabPtr == -1) {
  795.     dprintf("Vm_Mmap: Danger: sharedSeg->segTabPtr is -1!\n");
  796.     }
  797.     List_Insert((List_Links *)sharedSeg,
  798.         LIST_ATFRONT((List_Links *)procPtr->vmPtr->sharedSegs));
  799.     
  800.  
  801.     VmPrintSharedSegs(procPtr);
  802.     UNLOCK_SHM_MONITOR;
  803.     dprintf("Vm_Mmap: Completed page mapping\n");
  804.     *mappedAddr = startAddr;
  805.     if (debugVmStubs) {
  806.     printf("end of mmap: refCount = %d\n",
  807.         ((Fs_HandleHeader *)streamPtr)->refCount);
  808.     }
  809.     return SUCCESS;
  810. }
  811.  
  812. /*
  813.  *----------------------------------------------------------------------
  814.  *
  815.  * Vm_Munmap --
  816.  *
  817.  *    Unmaps the process's pages in a specified address range.
  818.  *    Gets the lock and then calls VmMunmapInt.
  819.  *
  820.  * Results:
  821.  *    Status from the unmap operation.
  822.  *
  823.  * Side effects:
  824.  *    Unmaps the pages.
  825.  *
  826.  *----------------------------------------------------------------------
  827.  */
  828. ReturnStatus
  829. Vm_Munmap(startAddr, length, noError)
  830.     Address    startAddr;    /* Starting virt-addr. */
  831.     int        length;        /* Length of mapped segment. */
  832.     int        noError;    /* Ignore errors. */
  833. {
  834.     ReturnStatus status;
  835.  
  836.     dprintf("munmap(%x, %d, %d)\n", startAddr, length, noError);
  837.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  838.     printf("Vm_Munmap: Invalid start or offset\n");
  839.     return VM_WRONG_SEG_TYPE;
  840.     }
  841.     LOCK_SHM_MONITOR;
  842.     status = VmMunmapInt(startAddr,length, noError);
  843.     UNLOCK_SHM_MONITOR;
  844.     return status;
  845. }
  846.  
  847. /*
  848.  *----------------------------------------------------------------------
  849.  *
  850.  * VmMunmapInt --
  851.  *
  852.  *    Unmaps the process's pages in a specified address range.
  853.  *
  854.  * Results:
  855.  *    Status from the unmap operation.
  856.  *
  857.  * Side effects:
  858.  *    Unmaps the pages.
  859.  *
  860.  *----------------------------------------------------------------------
  861.  */
  862. static ReturnStatus
  863. VmMunmapInt(startAddr, length, noError)
  864.     Address    startAddr;    /* Starting virt-addr. */
  865.     int        length;        /* Length of mapped segment. */
  866.     int        noError;    /* 1 if don't care about errors
  867.                    from absent segments. */
  868. {
  869.  
  870.     ReturnStatus    status = SUCCESS;
  871.     Proc_ControlBlock    *procPtr;
  872.     Vm_SegProcList        *segProcPtr;
  873.     Vm_SegProcList        *newSegProcPtr;
  874.     Address        addr;
  875.     Address        addr1;
  876.     Address        endAddr;
  877.     Vm_VirtAddr        virtAddr;
  878.  
  879.     virtAddr.flags = 0;
  880.     virtAddr.offset = 0;
  881.  
  882.     dprintf("Vm_Munmap: Unmapping shared pages\n");
  883.  
  884.     procPtr = Proc_GetCurrentProc();
  885.     endAddr = startAddr+length;
  886.     for (addr=startAddr; addr<endAddr; ) {
  887.  
  888.     dprintf("Vm_Munmap: trying to eliminate %x to %x\n",
  889.         (int)addr,(int)endAddr-1);
  890.     /* Find the segment corresponding to this address. */
  891.     if (procPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  892.         segProcPtr = VmFindSharedSegment(procPtr->vmPtr->sharedSegs,addr);
  893.     } else if (noError) {
  894.         return SUCCESS;
  895.     } else {
  896.         dprintf("Vm_Munmap: Process has no shared segments\n");
  897.         return VM_WRONG_SEG_TYPE;
  898.     }
  899.  
  900.     /* There are three possibilities:
  901.        1. The unmap can remove a mapping.
  902.        2. The unmap can shrink a mapping.
  903.        3. The unmap can split a mapping.
  904.     */
  905.  
  906.     if (segProcPtr == (Vm_SegProcList *)NIL) {
  907.         if (!noError) {
  908.         dprintf("Vm_Munmap: Page to unmap not in valid range\n");
  909.         status = VM_WRONG_SEG_TYPE;
  910.         }
  911.         /*
  912.          * Move to next mapped segment, so we can keep unmapping.
  913.          */
  914.         addr1 = endAddr;
  915.         LIST_FORALL(procPtr->vmPtr->sharedSegs,
  916.             (List_Links *)segProcPtr) {
  917.         if (segProcPtr->mappedStart > addr && 
  918.             segProcPtr->mappedStart < addr1) {
  919.             addr1 = segProcPtr->mappedStart;
  920.         }
  921.         }
  922.     } else {
  923.         addr1 = segProcPtr->mappedEnd+1;
  924.  
  925.         /*
  926.          * Invalidate the pages to be mapped out.
  927.          */
  928.         virtAddr.page = max((int)segProcPtr->mappedStart,(int)addr)
  929.             >> vmPageShift;
  930.         virtAddr.segPtr = segProcPtr->segTabPtr->segPtr;
  931.         virtAddr.sharedPtr = segProcPtr;
  932.         dprintf("Vm_Munmap: invalidating: %x to %x\n",
  933.             (int)virtAddr.page<<vmPageShift,
  934.             min((int)segProcPtr->mappedEnd+1, (int)endAddr));
  935.         VmFlushSegment(&virtAddr,min((int)segProcPtr->mappedEnd+1,
  936.             (int)endAddr)>>vmPageShift);
  937.  
  938.         if (segProcPtr->mappedStart < addr) {
  939.         dprintf("Vm_Munmap: Shortening mapped region (1)\n");
  940.         if (segProcPtr->mappedEnd >= endAddr) {
  941.             dprintf("Vm_Munmap: Splitting mapped region\n");
  942.             /*
  943.              * Split the mapped region.
  944.              */
  945.             newSegProcPtr = (Vm_SegProcList *)
  946.                 malloc(sizeof(Vm_SegProcList));
  947.             if (debugVmStubs) {
  948.             printf("Malloc'd %x\n", newSegProcPtr);
  949.             }
  950.             *newSegProcPtr = *segProcPtr;
  951.             newSegProcPtr->mappedStart = endAddr;
  952.             newSegProcPtr->mappedEnd = segProcPtr->mappedEnd;
  953.             segProcPtr->segTabPtr->refCount++;
  954.             List_Insert((List_Links *)newSegProcPtr, LIST_AFTER(
  955.                 (List_Links *)segProcPtr));
  956.         }
  957.         /*
  958.          * Shrink the first mapping.
  959.          */
  960.         segProcPtr->mappedEnd = addr-1;
  961.         } else if (segProcPtr->mappedEnd >= endAddr) {
  962.         /*
  963.          * Shrink the mapped region.
  964.          */
  965.         dprintf("Vm_Munmap: Shortening mapped region (2)\n");
  966.         segProcPtr->mappedStart = endAddr;
  967.         } else {
  968.         dprintf("Vm_Munmap: Removing mapped region\n");
  969.         /*
  970.          * Remove the entire mapped region.
  971.          */
  972.         Vm_DeleteSharedSegment(procPtr,segProcPtr);
  973.         }
  974.     }
  975.     if (addr == addr1) {
  976.         panic("Vm_Munmap loop\n");
  977.     }
  978.     addr = addr1;
  979.     }
  980.  
  981.     VmPrintSharedSegs(procPtr);
  982.     dprintf("Vm_Munmap: done\n");
  983.     return status ;
  984. }
  985.  
  986. /* 
  987.  * Check if an address range is valid for the segment.
  988.  */
  989. #define CheckBounds(virtAddrPtr,startAddr,length) \
  990.     ((unsigned)(((int)(startAddr)>>vmPageShift) - segOffset(virtAddrPtr)) \
  991.     < (virtAddrPtr)->segPtr->ptSize && \
  992.     ((unsigned)((((int)(startAddr)+(length)-1)>>vmPageShift) - \
  993.     segOffset(virtAddrPtr)) < (virtAddrPtr)->segPtr->ptSize))
  994. /*
  995.  *----------------------------------------------------------------------
  996.  *
  997.  * Vm_Msync --
  998.  *
  999.  *    Sync pages to disk.
  1000.  *    startAddr and length must be divisible by the page size.
  1001.  *
  1002.  * Results:
  1003.  *    Status from the sync.
  1004.  *
  1005.  * Side effects:
  1006.  *    Page goes to disk.
  1007.  *
  1008.  *----------------------------------------------------------------------
  1009.  */
  1010. ENTRY ReturnStatus
  1011. Vm_Msync(startAddr, length)
  1012.     Address    startAddr;    /* Requested starting virt-addr. */
  1013.     int        length;        /* Length of region to page out. */
  1014. {
  1015.     Vm_VirtAddr        virtAddr;
  1016.     ReturnStatus    status;
  1017.     Proc_ControlBlock    *procPtr;
  1018.  
  1019.     dprintf("msync( %x, %d)\n", startAddr, length);
  1020.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1021.     printf("Vm_Msync: Invalid start or offset\n");
  1022.     return VM_WRONG_SEG_TYPE;
  1023.     }
  1024.     LOCK_SHM_MONITOR;
  1025.     procPtr = Proc_GetCurrentProc();
  1026.     VmVirtAddrParseUnlock(procPtr, startAddr, &virtAddr);
  1027.     if (virtAddr.segPtr == (Vm_Segment *)NIL || !CheckBounds(&virtAddr,
  1028.         startAddr, length)) {
  1029.     UNLOCK_SHM_MONITOR;
  1030.     return SYS_INVALID_ARG;
  1031.     }
  1032.     status = VmPageFlush(&virtAddr, length, TRUE, TRUE);
  1033.     UNLOCK_SHM_MONITOR;
  1034.     return status;
  1035. }
  1036.  
  1037. /*
  1038.  *----------------------------------------------------------------------
  1039.  *
  1040.  * Vm_Mlock --
  1041.  *
  1042.  *    Locks a page into memory.  Page is paged in if necessary.
  1043.  *
  1044.  * Results:
  1045.  *    Fails if unable to lock page.
  1046.  *
  1047.  * Side effects:
  1048.  *    Locks the page.
  1049.  *
  1050.  *----------------------------------------------------------------------
  1051.  */
  1052. /*ARGSUSED*/
  1053. ENTRY ReturnStatus
  1054. Vm_Mlock(startAddr, length)
  1055.     Address    startAddr;    /* Requested starting virt-addr. */
  1056.     int        length;        /* Length of region to lock. */
  1057. {
  1058.     Vm_VirtAddr        virtAddr;
  1059.     Proc_ControlBlock    *procPtr;
  1060.     int            maptype = VM_READWRITE_ACCESS;
  1061.  
  1062.     dprintf("mlock( %x, %d)\n", startAddr, length);
  1063.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1064.     printf("Vm_Mlock: Invalid start or offset\n");
  1065.     return VM_WRONG_SEG_TYPE;
  1066.     }
  1067.     procPtr = Proc_GetCurrentProc();
  1068.     VmVirtAddrParseUnlock(procPtr, startAddr, &virtAddr);
  1069.     if (virtAddr.segPtr == (Vm_Segment *)NIL || !CheckBounds(&virtAddr,
  1070.         startAddr, length)) {
  1071.     return SYS_INVALID_ARG;
  1072.     } else if (virtAddr.sharedPtr != (Vm_SegProcList *)NIL) {
  1073.     maptype = virtAddr.sharedPtr->prot == VM_READONLY_SEG ?
  1074.         VM_READONLY_ACCESS : VM_READWRITE_ACCESS;
  1075.     } else {
  1076.     maptype = virtAddr.segPtr->type == VM_CODE ? VM_READONLY_ACCESS :
  1077.         VM_READWRITE_ACCESS;
  1078.     }
  1079.     return Vm_PinUserMem(maptype,length,startAddr);
  1080. }
  1081.  
  1082. /*
  1083.  *----------------------------------------------------------------------
  1084.  *
  1085.  * Vm_Munlock --
  1086.  *
  1087.  *    Unlocks a page.
  1088.  *
  1089.  * Results:
  1090.  *    Status from the unlock.
  1091.  *
  1092.  * Side effects:
  1093.  *    Unlocks the page.
  1094.  *
  1095.  *----------------------------------------------------------------------
  1096.  */
  1097. /*ARGSUSED*/
  1098. ENTRY ReturnStatus
  1099. Vm_Munlock(startAddr, length)
  1100.     Address    startAddr;    /* Requested starting virt-addr. */
  1101.     int        length;        /* Length of region to unlock. */
  1102. {
  1103.     Vm_VirtAddr    virtAddr;
  1104.     Proc_ControlBlock    *procPtr;
  1105.  
  1106.     dprintf("munlock( %x, %d)\n", startAddr, length);
  1107.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1108.     printf("Vm_Munlock: Invalid start or offset\n");
  1109.     return VM_WRONG_SEG_TYPE;
  1110.     }
  1111.     procPtr = Proc_GetCurrentProc();
  1112.     VmVirtAddrParseUnlock(procPtr, startAddr, &virtAddr);
  1113.     if (virtAddr.segPtr == (Vm_Segment *)NIL || !CheckBounds(&virtAddr,
  1114.         startAddr, length)) {
  1115.     return SYS_INVALID_ARG;
  1116.     }
  1117.     Vm_UnpinUserMem(length,startAddr);
  1118.     return SUCCESS;
  1119. }
  1120.  
  1121. /*
  1122.  *----------------------------------------------------------------------
  1123.  *
  1124.  * Vm_Mincore --
  1125.  *
  1126.  *    Returns residency vector.
  1127.  *
  1128.  * Results:
  1129.  *    The values of vec are 0 if the page is not virtually resident,
  1130.  *    1 if the page is paged out, 2 if the page is clean and
  1131.  *    untouched, 3 if the page is referenced, and 4 if the page is dirty.
  1132.  *
  1133.  * Side effects:
  1134.  *    None.
  1135.  *
  1136.  *----------------------------------------------------------------------
  1137.  */
  1138. /*ARGSUSED*/
  1139.  
  1140. ENTRY ReturnStatus
  1141. Vm_Mincore(startAddr, length, retVec)
  1142.     Address    startAddr;    /* Requested starting virt-addr. */
  1143.     int        length;        /* Length of region. */
  1144.     char *    retVec;        /* Return vector. */
  1145. {
  1146.     char        *vec;
  1147.     Address        checkAddr;
  1148.     Vm_VirtAddr        virtAddr;
  1149.     Proc_ControlBlock    *procPtr;
  1150.     ReturnStatus    status;
  1151.     int            len;
  1152.     int            i;
  1153.     Vm_PTE        *ptePtr;
  1154.     Boolean        referenced;
  1155.     Boolean        modified;
  1156.  
  1157.     dprintf("mincore( %x, %d, %x)\n", startAddr, length, retVec);
  1158.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1159.     printf("Vm_Mincore: Invalid start or offset\n");
  1160.     return VM_WRONG_SEG_TYPE;
  1161.     }
  1162.     procPtr = Proc_GetCurrentProc();
  1163.     len = length>>vmPageShift;
  1164.     vec = (char *)malloc(len);
  1165.     checkAddr = startAddr;
  1166.     for (i=0;i<len;i++) {
  1167.     VmVirtAddrParseUnlock(procPtr, checkAddr, &virtAddr);
  1168.     if (virtAddr.segPtr == (Vm_Segment *)NIL) {
  1169.         vec[i] = 0;
  1170.         dprintf("Vm_Mincore: no segment at address %x\n", checkAddr);
  1171.     } else {
  1172.         ptePtr = VmGetAddrPTEPtr(&virtAddr, virtAddr.page);
  1173.         if (*ptePtr & VM_VIRT_RES_BIT) {
  1174.         if (*ptePtr & VM_PHYS_RES_BIT) {
  1175.             VmMach_GetRefModBits(&virtAddr, Vm_GetPageFrame(*ptePtr),
  1176.                 &referenced, &modified);
  1177.             if (modified || (*ptePtr & VM_MODIFIED_BIT)) {
  1178.             vec[i] = 4;
  1179.             dprintf("Vm_Mincore: modified at %x\n", checkAddr);
  1180.             } else if (referenced || (*ptePtr & VM_REFERENCED_BIT)) {
  1181.             vec[i] = 3;
  1182.             dprintf("Vm_Mincore: referenced at %x\n", checkAddr);
  1183.             } else {
  1184.             vec[i] = 2;
  1185.             dprintf("Vm_Mincore: present at %x\n", checkAddr);
  1186.             }
  1187.         } else {
  1188.             vec[i] = 1;
  1189.             dprintf("Vm_Mincore: absent at %x\n", checkAddr);
  1190.         }
  1191.         } else {
  1192.         vec[i] = 0;
  1193.         dprintf("Vm_Mincore: gone at %x\n", checkAddr);
  1194.         }
  1195.     }
  1196.     checkAddr += vm_PageSize;
  1197.     dprintf("Vm_Mincore: i=%d v[i]=%d\n",i,vec[i]);
  1198.     }
  1199.     status = Vm_CopyOut( len, (Address) vec, (Address) retVec);
  1200.     free((char *)vec);
  1201.     return status;
  1202. }
  1203.  
  1204. /*
  1205.  *----------------------------------------------------------------------
  1206.  *
  1207.  * Vm_Mprotect --
  1208.  *
  1209.  *    Change protection of pages.
  1210.  *
  1211.  * Results:
  1212.  *    SUCCESS or error condition.
  1213.  *
  1214.  * Side effects:
  1215.  *    Changes protection.
  1216.  *
  1217.  *----------------------------------------------------------------------
  1218.  */
  1219.  
  1220. ENTRY ReturnStatus
  1221. Vm_Mprotect(startAddr, length, prot)
  1222.     Address    startAddr;    /* Requested starting virt-addr. */
  1223.     int        length;        /* Length of region. */
  1224.     int        prot;        /* Protection for region. */
  1225. {
  1226.     Vm_VirtAddr virtAddr;
  1227.     Vm_PTE          *ptePtr;
  1228.     Proc_ControlBlock       *procPtr;
  1229.     int i;
  1230.     int firstPage, lastPage;
  1231.  
  1232.     if (BADALIGN(startAddr) || BADALIGN(length)) {
  1233.     printf("Vm_Mprotect: Invalid start or offset\n");
  1234.     return VM_WRONG_SEG_TYPE;
  1235.     }
  1236. #if 0
  1237.     if (prot & ~(PROT_READ|PROT_WRITE)) {
  1238.     printf("Vm_Mprotect: Only read/write permissions allowed\n");
  1239.     return SYS_INVALID_ARG;
  1240.     }
  1241. #endif
  1242.     if (!(prot & PROT_READ)) {
  1243.     printf("Vm_Mprotect: can't remove read perms in this implementation\n");
  1244.     return SYS_INVALID_ARG;
  1245.     }
  1246.     procPtr = Proc_GetCurrentProc();
  1247.     VmVirtAddrParseUnlock(procPtr, startAddr, &virtAddr);
  1248.     firstPage = (unsigned int) startAddr >> vmPageShift;
  1249.     lastPage = ((unsigned int)(startAddr+length-1)) >> vmPageShift;
  1250.     if (firstPage < segOffset(&virtAddr)) {
  1251.     printf("First page is out of range\n");
  1252.     return SYS_INVALID_ARG; /* ENOMEM */
  1253.     }
  1254.     for (i=lastPage-firstPage, ptePtr =
  1255.         VmGetAddrPTEPtr(&virtAddr, virtAddr.page);i>=0;
  1256.         i--, VmIncPTEPtr(ptePtr,1), virtAddr.page++) {
  1257.     if (virtAddr.page >= segOffset(&virtAddr) + virtAddr.segPtr->ptSize) {
  1258.         printf("Page %d out of range\n",virtAddr.page);
  1259.         printf("Addr = %x, segOffset=%d, ptSize=%d, segType %d\n", startAddr,
  1260.             segOffset(&virtAddr), virtAddr.segPtr->ptSize,
  1261.             virtAddr.segPtr->type);
  1262.         break;
  1263.     }
  1264.     if (prot & PROT_WRITE) {
  1265.         *ptePtr &= ~VM_READ_ONLY_PROT;
  1266.     } else {
  1267.         *ptePtr |= VM_READ_ONLY_PROT;
  1268.     }
  1269.     VmMach_SetPageProt(&virtAddr, *ptePtr);
  1270.     }
  1271.     return SUCCESS;
  1272. }
  1273.